--
-- Author: shunguo.chen
-- Date: 2018-08-14 14:09:32
--
-- LoadingController
--

local TaskSequence = require("app.utils.TaskSequence")
local LoadingView = import("..views.LoadingView")

local Director = cc.Director:getInstance()
local TextureCache = Director:getTextureCache()
local FileUtils = cc.FileUtils:getInstance()

local fileName = string.getModeName(...)
local ClassRef = class(fileName, app.mvc.ControllerBase)

function ClassRef:ctor(data)
    self.super.ctor(self, data)
end

function ClassRef:init()
    self._model = app:getInst("LoadingModel")

    self._isInLoading = false
end

function ClassRef:removeListeners()
    self.super.removeListeners(self)

end

function ClassRef:listEvent()
    return {
        "OnGameConnected"
    }
end

function ClassRef:onEvent(eventName, ...)
    local data = ...
    if eventName == "OnGameConnected" then
        local node = Director:getRunningScene():getChildByName("HotFixScene")
        if not cc.isDead(node) then
            node:removeFromParent(true)
        end
    end
end

-- data = mapId
function ClassRef:openView(data)
    if cc.isDead(self._view) then
        self._view = LoadingView.new()
        self._view:onCloseView(handler(self, self.closeView))
        self._view:onClearView(handler(self, self.clearView))
        self._view:onOperate(handler(self, self.onOperate))
        self:addChild(self._view, data)
    end

    self._view:setBg(self._model:getMapLoadingImg(data))
    self._view:setTips(self._model:getMapLoadingTips())

    self._view:show()
end
function ClassRef:clearView()
    if self._view then
        self._view = nil
    end
end

function ClassRef:isInLoading()
    return self._isInLoading
end


function ClassRef:_showMessageBox(msg, cb1, cb2)
    -- apple 提审 读取进度条 显示 不消耗流量
    if app.channelAPI:isReview()  then
        local confirmDialog = display.newConfirmDialog(msg, function()
            if cb1 then
                cb1()
            end
        end, function()
            if cb2 then
                cb2()
            else
                -- app:exit()
            end
        end)
        confirmDialog:setConfirmText("Yes")
        confirmDialog:setCancelText("No")
        cc.Director:getInstance():getRunningScene():addChild(confirmDialog, 1000)
    else
        if cb1 then
            cb1()
        end
    end
end


-- function ClassRef:gameInitLoading()
--     self:_showMessageBox(L("InitNotCostCellularData"),function()
--         self:_gameInitLoading()
--     end)
-- end

-- 游戏初始化loading
function ClassRef:gameInitLoading()

    local scene = Director:getRunningScene()
    local node = scene:findChild("HotFixScene/hotfix/Panel")
    
    local typeEmulator = device.getEmulatorType()
    if ENABLE_IGNORE_EMULATOR or ENABLE_IGNORE_PAD or ENABLE_IGNORE_LOW_CPU_FREQ or ENABLE_IGNORE_LOW_MEMORY then
        local SettingHelp = require("app.utils.SettingHelp")
        local platform = cc.Application:getInstance():getTargetPlatform()
        local cpuFreq = SettingHelp.getCpuInfo()
        local memoryLevel = SettingHelp.getMemoryLevel()
        local flagPad = device.isPad()
        release_print("=========> LoadingController:gameInitLoading()")
        release_print("=========> cpuFreq:", cpuFreq)
        release_print("=========> memoryLevel:", memoryLevel)
        release_print("=========> EmulatorType:", typeEmulator)
        release_print("=========> isPad:", flagPad)

        local isStopEnter = false
        local function checkFuncIgnoreEmulator()
            if ENABLE_IGNORE_EMULATOR then
                -- 不拦截腾讯手游助手
                if typeEmulator > Enums.EmulatorType.Phone and typeEmulator ~= Enums.EmulatorType.Tencent then
                    return true
                end
            end
            return false
        end

        local function checkFuncIgnorePad()
            if ENABLE_IGNORE_PAD then
                -- 不拦截 ios pad
                if not app:isIOS() and flagPad then
                    return true
                end
            end
            return false
        end

        local function checkLowCpu()
            if ENABLE_IGNORE_LOW_CPU_FREQ then
                if cpuFreq and cpuFreq < LOW_CPU_FREQ then
                    return true
                end
            end
            return false
        end

        local function checkLowMemory()
            if ENABLE_IGNORE_LOW_MEMORY then
                if platform == cc.PLATFORM_OS_ANDROID then
                    if memoryLevel <= SettingHelp.VERY_LOW then
                        return true
                    end
                else
                    if not app.channelAPI:isReview() and memoryLevel <= SettingHelp.LOW then
                        return true
                    end
                end
                return false
            end
        end
        local checkFuncs = {
            checkFuncIgnoreEmulator,
            checkFuncIgnorePad,
            checkLowCpu,
            checkLowMemory
        }

        for k, checkF in pairs(checkFuncs) do
            if checkF() then
                isStopEnter = true
                break
            end
        end

        if isStopEnter then
            GemService:SetEvent(12, false, "cpu not fit", false, false)
            node:setVisible(false)
            local LoginNoticeView = require("app.login.views.LoginNoticeView")
            local view = LoginNoticeView.new()
            view:setData({
                {
                    title = L("lua_code_text_36"),
                    titleType = 0,
                    priority = 0,
                    content = ENABLE_IGNORE_NOTICE_CONTENT,
                    buttonUrl = "",
                }
            })
            view:setClostBtnVisible(false)
            local parentNode = scene:findChild("HotFixScene/hotfix")
            parentNode:addChild(view)
            return
        end
    end

    if typeEmulator > Enums.EmulatorType.Tencent then
        local LoginNoticeView = require("app.login.views.LoginNoticeView")
        local view = LoginNoticeView.new()
        view:setData({
            {
                title = L("lua_code_text_36"),
                titleType = 0,
                priority = 0,
                content = EMULATOR_TENCENT_NOTICE_CONTENT,
                buttonUrl = "",
            }
        })
        view:setOpenUrlDelegate(function(url)
            device.openURL(url)
        end)
        local parentNode = scene:findChild("HotFixScene/hotfix")
        parentNode:addChild(view, 1001)
    end

    GemService:SetEvent(12, true, "success", false, false)
   
    EM:notify("OnGameInitStart")
    local gameInitStartTime = os.time()

    local barFile, barTotal, tipText, perText, lightTag
    local barPos
    if node then
        node:findChild("Loading"):setVisible(true)
        node:findChild("Loading_1"):setVisible(true)

        barFile = node:findChild("Loading_1/LoadingBar")
        barTotal = node:findChild("Loading/LoadingBar")
        tipText = node:findChild("Text_4")
        perText = node:findChild("Loading/Text_2")
        lightTag = node:findChild("Loading/light_layout/light")

        local width = barTotal:getContentSize().width
        barPos = barTotal:getAnchorPointInPoints()
        barPos.x = barPos.x - width*0.5
    end

    local isBattleGuideComp = app:isBattleGuideComp()
    local taskSeq = TaskSequence.new()
    taskSeq:setProgressCallback(function(sender, percent)
        if cc.isDead(node) then return end
        if not barTotal then return end

        if barFile then
            barFile:setPercent(percent)
        end
        barTotal:setPercent(percent)
        if tipText then
            tipText:setVisible(true)
            tipText:setString(L("lua_code_text_455"))
        end
        if perText then
            perText:setVisible(true)
            perText:setString(percent .. "%")
        end

        if lightTag then
            local pos = cc.p(barPos.x+width*(percent*0.01), barPos.y)
            local wp = barTotal:convertToWorldSpace(pos)
            local lp = lightTag:getParent():convertToNodeSpace(wp)
            lightTag:setPosition(lp)
        end
    end)

    taskSeq:setFinishCallback(function()
        if not cc.isDead(node) then
            node:setVisible(false)
        end

        if not isBattleGuideComp then
            -- 移除 HotFixScene
            local hotFixScene = scene:getChildByName("HotFixScene")
            if not cc.isDead(hotFixScene) then
                hotFixScene:removeFromParent(true)
            end
        end

        self._isInLoading = false
    end)

    taskSeq:addTask(function()
        local chunksFile = "res/scripts.zip"
        if FileUtils:isFileExist(chunksFile) then
            cc.LuaLoadChunksFromZIP(chunksFile)
        end
    end)

    --_RelaunchAppAction 1 切换角色，切换角色不需要清理所有的缓存
    local isSwitchPlayer = (_RelaunchAppAction == 1)

    if not isSwitchPlayer then
        GD:removeAllCache()

        local dbcaches = require("app.public.gamedb.GameDBCaches")
        for name,v in pairs(dbcaches) do
            taskSeq:addTask(function()
                GD:reloadCache(name, v.key)
            end)
        end
    end

    taskSeq:addTask(function()
        St = require("app.scripts.Script")
    end)

    taskSeq:addTask(function()
        local protobuf = require("protobuf")
        protobuf.register(cc.HelperFunc:getFileData("src/protocol/protocol.pb"))
        if DEBUG >0 then
            protobuf.check_messages()
        end
    end)

    local modules = app.modules
    for i,name in ipairs(modules) do
        taskSeq:addTask(function()
            require(name .. ".init")
        end)
    end

    if not isSwitchPlayer then
        taskSeq:addTask(function()
            db.BaseObject:clearPool(-1)
            db.BaseObject:setMaxCount(db.BoneFrameData:getTypeIndex(),100000)
            db.BaseObject:setMaxCount(db.SlotFrameData:getTypeIndex(),40000)
            -- 登陆有骨骼动画，不能清理
            -- db.CCFactory:getInstance():clear()

            --ActionManager:removeAllActions()
            -- ActionManagerEx:releaseActions()
            cc.CSLoader:getInstance():purge()
            Director:purgeCachedData()
        end)
    end

    taskSeq:addTask(function()
        --读取battleconfig
        battle.BattleConfig:getInstance():setFileLoader(battle.ClientFileLoader:getInstance())
        battle.BattleConfig:getInstance():load("config/")
        --重新加载数据后需要清除 buff 数据缓存
        require("app.battleV3.models.BuffModel"):clearCache()

    end)

    taskSeq:addTask(function()
        --load battle script
        battle.ScriptManager:Instance():load("scripts/battle/", battle.ClientFileLoader:getInstance())

        if battle.texture then
            battle.texture:release()
            battle.texture = nil
        end
    end)

    if not isSwitchPlayer then
        --preload battle ui
        if cc.CSLoader.preload then
            local battleCSBList={
                Res.BattleUINew,
                Res.BattlePlayerHead,
                Res.NewBattleStatusBar,
                Res.BattleBossFloatText,
                Res.BattleEffect_HurtText,
                Res.BattleEffect_CritText,
                Res.BattleEffect_MissText,
                Res.BattleEffect_ImmunityText,
            }
            -- TODO BattleUINew 应该被优化，太大了
            for i,v in ipairs(battleCSBList) do
                taskSeq:addTask(function()
                    cc.CSLoader:preload({v},function(count)
                    -- print("====>cc.CSLoader:preload",count)
                    end)
                end)
            end
        end
    end

    taskSeq:addTask(function()
        -- 预加载触发器
        require("app.battleV3.VisualEffect").prepareLoadTriggers()

        app:run()
    end)

    if not isBattleGuideComp then
        local mapId = 101

        taskSeq:addTask(function()
            MapManager:setMapId(mapId)
            local launchCtl = require("app.world.controllers.LaunchController").new()
            scene:addChild(launchCtl, 0, 1)
            app:setLaunchCtl(launchCtl)
            launchCtl:init()
        end)

        local preLoadTasks = self._model:getLoadTextureTasks(mapId)
        for i,task in ipairs(preLoadTasks) do
            taskSeq:addTask(task)
        end

        taskSeq:addTask(function()
            TaskManager:updateBaseShowIds()
            NpcManager:loadAllNpcConfigs(mapId)
        end)

        taskSeq:addTask(function()
            NpcFactory:createAllMapBaseNpc(mapId)
        end)

        taskSeq:addTask(function()
            NpcFactory:createTaskBaseNpcs(mapId)
        end)

        taskSeq:addTask(function()
            AM.stopAll()
            MapManager:doEnterMap(mapId, nil, GUIDE_BATTLE_INIT_MAP_POS)
        end)

        taskSeq:addTask(function()
            MapManager:switchOverCallback()
        end)

        taskSeq:addTask(function()
            local AvatarFactory = app:getClass("AvatarFactory")
            local guideRoles = app:sendMsg("NewerbattleguideModel", "getGuideRoles")
            for i,role in ipairs(guideRoles) do
                AvatarFactory.preloadHero(role:getBaseInfo())
            end
        end)

        -- 添加助战单位资源/怪物
        local battleNpcIds = {
                    20009901, 
                    20009902, 
                    20009903, 
                    20009904, 
                    20009918, 
                    20009919,
                    20009929,
                    20009905,
                    20009906,
                    20009907,
                    20009915,
                    20009926,
                }
        local step = 0
        local npcLen = #battleNpcIds
        while step <= npcLen do
            local ids = {}
            for i=1, 3 do
                local idx = i + step
                if idx > npcLen then
                    break
                end
                ids[#ids + 1] = battleNpcIds[idx]
            end

            if #ids > 0 then
                taskSeq:addTask(function()
                    local AvatarFactory = app:getClass("AvatarFactory")
                    for i,id in ipairs(ids) do
                        AvatarFactory.preloadNpcById(id)
                    end
                end)
            end

            step = step + 3
        end

        taskSeq:addTask(function()
            local gameInitEndTime = os.time()
            EM:notify("OnGameInitEnd", gameInitEndTime - gameInitStartTime)
            app:sendMsg("NewerbattleguideController", "beginBattleGuide")
        end)
    else
        taskSeq:addTask(function()
            print("====================>> game init open login view")
            local gameInitEndTime = os.time()
            EM:notify("OnGameInitEnd", gameInitEndTime - gameInitStartTime)
            app:openLoginView()
        end)
    end

    scene:addChild(taskSeq)
    taskSeq:start()
    self._isInLoading = true
end

function ClassRef:leaveBattleGuide()
    local launchCtl = app:getLaunchCtl()
    launchCtl:stopUpdateFrame()
    
    if BattleManager:isBattle() then
        BattleManager:goOutBattle()
    end
    MapManager:setHasChangeMapNextEvent(false)
    MapManager:doLeaveMap()
    app:purgeUnusedTextures()
end

function ClassRef:checkMapValid(mapId, isFirstMap)
    local errorMsg = app:checkMapRes(mapId)
    if errorMsg then
        local msgNode = display.newMessageBox(errorMsg, function()
            if isFirstMap then
                app:relaunchApp()
            end
        end)
        UIHandler:addPopDialog(msgNode)
        return false
    end
    return true
end


-- function ClassRef:enterMapLoading(msg)
--     self:_showMessageBox(L("LoadMapNotCostCellularData"), function()
--         self:_enterMapLoading(msg)
--     end)
-- end

-- 进入地图loading，选角第一次进入游戏
function ClassRef:enterMapLoading(msg)
    local mapId = msg.mapId
    local posX = msg.posX
    if not self:checkMapValid(mapId, true) then return end

    local gameScene = Director:getRunningScene()

    MapManager:setMapId(mapId)
    if not app:getLaunchCtl() then
        local launchCtl = require("app.world.controllers.LaunchController").new()
        gameScene:addChild(launchCtl, 0, 1)
        app:setLaunchCtl(launchCtl)
        launchCtl:init()
    end

    local view = LoadingView.new()
    view:setBg(self._model:getMapLoadingImg(mapId))
    view:setTips(self._model:getMapLoadingTips())
    gameScene:addChild(view, 1)

    local taskSeq = TaskSequence.new()
    gameScene:addChild(taskSeq)

    taskSeq:setFinishCallback(function()
        view:removeFromParent()
        self._isInLoading = false
    end)

    taskSeq:setProgressCallback(function(sender, percent)
        view:setProgress(percent)
    end)

    -- 拉游戏服务器公告
    taskSeq:addTask(function()
        require("app.login.models.gameSeverNoticeModel"):requestGameSeverNoticeList()
    end)

    taskSeq:addTask(function()
        display.purgeUnUsedArmatureCachedData()
        TextureCache:removeUnusedTextures()
        cc.SpriteFrameCache:getInstance():removeUnusedSpriteFrames()
    end)

    -- 本地推送
    taskSeq:addTask(function()
        app.notificationAPI:registShedules()

        -- ema 先清空
        app.channelAPI:deletePushData()

        local confs = GD:getPigeonFreeConfs()
        for i,conf in ipairs(confs) do
            if conf.ID ~= "1009" and conf.ID ~= "1010" then
                app:sendMsg("PlayerController", "addPushNotice", conf)
            end
        end
    end)

    local preLoadTasks = self._model:getLoadTextureTasks(mapId)
    for _,task in pairs(preLoadTasks) do
         taskSeq:addTask(task)
    end

    taskSeq:addTask(function()
        TaskManager:updateBaseShowIds()
        NpcManager:loadAllNpcConfigs(mapId)
    end)

    taskSeq:addTask(function()
        local resourcePointNpcUidList = NpcFactory:createAllResourcePoints(mapId, true)
        NpcManager:setResourcePointNpcUidList(resourcePointNpcUidList)
    end)

    taskSeq:addTask(function()
        NpcFactory:createAllMapBaseNpc(mapId)
    end)

    taskSeq:addTask(function()
        NpcFactory:createTaskBaseNpcs(mapId)
    end)

    taskSeq:addTask(function()
        -- 创建灰烬入侵战斗NPC
        local grayBattleNpcUidList = NpcFactory:createGrayBattleNpcs(mapId, true)
        NpcManager:setGrayBattleNpcUidList(grayBattleNpcUidList)
    end)

    taskSeq:addTask(function()
        MapManager:doEnterMap(mapId, nil, posX)
    end)

    taskSeq:addTask(function()
        MapManager:switchOverCallback(true)
    end)

    taskSeq:start()
    self._isInLoading = true
end

-- 切换地图loading
-- -- params = {
--    mapId    地图id
--    transNpcId    目标npcId
--    first    是否第一次进入地图（登录游戏后的第一次）
--    transX    地图目标点x坐标
--    service    是否是服务器发来的消息驱动
--    confirmNpcId    确定npcId，从配置获取地图或地下城等信息
-- }

-- function ClassRef:changeMapLoading(params)
--     self:_showMessageBox(L("LoadMapNotCostCellularData"), function()
--         self:_changeMapLoading(params)
--     end)
-- end

function ClassRef:changeMapLoading(params)
    local mapId = params.mapId
    local transNpcId = params.transNpcId
    local first = params.first
    local transX = params.transX
    local service = params.service
    local confirmNpcId = params.confirmNpcId

    local mapConfig = GD:queryMapById(mapId)
    local launchCtl = app:getLaunchCtl()

    MapManager:setMapId(mapId)

    -- 修正 transX，transNpcId
    local sx,sy,tTransNpcId = FieldManager:getCharacterStartPos(transNpcId, mapId)
    transNpcId = tTransNpcId
    if transX then sx = transX end

    local MapManager = _G["MapManager"]

    -- start into map
    launchCtl:stopUpdateFrame()
    MapManager:setHasChangeMapNextEvent(false)

    FieldManager:setCharacterX(sx)
    EM:notify("onIntoMap",{mapName = L(mapConfig.string)})

    -- add LoadingView
    local view = LoadingView.new()
    view:setBg(self._model:getMapLoadingImg(mapId))
    view:setTips(self._model:getMapLoadingTips())
    launchCtl:addChild(view, SceneZOrder.loadingZOrder)

    -- init TaskSequence
    local taskSeq = TaskSequence.new()
    launchCtl:addChild(taskSeq)

    taskSeq:setFinishCallback(function()
        view:removeFromParent()
        EM:notify("onLoadingComp")
        self._isInLoading = false
    end)

    taskSeq:setProgressCallback(function(sender, percent)
        view:setProgress(percent)
        EM:notify("onLoadingUp", percent)
    end)

    taskSeq:addTask(function()
        MapManager:doLeaveMap()
        MapManager:switchStartCallback()
    end)

    taskSeq:addTask(function()
        app:purgeUnusedTextures()
    end)

    local preLoadTasks = self._model:getLoadTextureTasks(mapId)
    for _,task in pairs(preLoadTasks) do
        taskSeq:addTask(task)
    end

    -- 如果是角色扮演，预加载角色
    local playId = self._model:getPlayId()
    local roles = app:sendMsg("CosplayModel", "getRolesByPlayId", playId)
    -- print("changeMapLoading", playId, roles and #roles or 0)
    self._model:setPlayId()
    if roles then
        local AvatarFactory = app:getClass("AvatarFactory")
        for _,role in ipairs(roles) do
            local task = function()
                AvatarFactory.preloadHero(role:getAvatarParams())
            end
            taskSeq:addTask(task)
        end
    end

    taskSeq:addTask(function()
        MapManager:doEnterMap(mapId,transNpcId,transX)
    end)

    taskSeq:addTask(function()
        TaskManager:updateBaseShowIds()
        NpcManager:loadAllNpcConfigs(mapId)
    end)
    taskSeq:addTask(function()
        local resourcePointNpcUidList = NpcFactory:createAllResourcePoints(mapId, true)
        NpcManager:setResourcePointNpcUidList(resourcePointNpcUidList)
    end)
    taskSeq:addTask(function()
        NpcFactory:createAllMapBaseNpc(mapId)
    end)

    taskSeq:addTask(function()
        NpcFactory:createTaskBaseNpcs(mapId)
    end)

    taskSeq:addTask(function()
        -- 创建灰烬入侵战斗NPC
        local grayBattleNpcUidList = NpcFactory:createGrayBattleNpcs(mapId, true)
        NpcManager:setGrayBattleNpcUidList(grayBattleNpcUidList)
    end)

    taskSeq:addTask(function()
        app:purgePolygons()
    end)

    taskSeq:addTask(function()
        MapManager:switchOverCallback()
    end)

    taskSeq:start()
    self._isInLoading = true
end

-------------------------------------------------------


-------------------------------------------------------
function ClassRef:onOperate(op, data)
    print("LoadingController:onOperate op", op)
    if op == "" then

    end
end

return ClassRef
